﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Configuration;

namespace Sunny.Lib
{
    public class HttpRequestClient
    {
        private HttpRequestConfiguration configuration = null;
        private List<Action<HttpWebRequest>> addPropertyOfHttpRequestActions = new List<Action<HttpWebRequest>>();
        public HttpRequestClient(HttpRequestConfiguration configuration)
        {
            this.configuration = configuration;
        }

        public ResponseResult HttpSendMessage()
        {
            // Client authorize server, if CheckValidationResult function return false, client stop to communicate with server
            ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);

            // Set request object properties value
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(configuration.RequestMethod == RequestMethodType.Post ? configuration.RequestUrl : string.Format("{0}?{1}", configuration.RequestUrl, configuration.RequestParameters));
            request.Method = configuration.RequestMethod.ToString();                  // Request method: Post or Get
            request.ContentType = configuration.RequestContentType;                   // Body type

            LoadActions(request);
            //request.PreAuthenticate = true;                 //Gets or sets a value that indicates whether to send an Authorization header with the request.
            request.Timeout = 600 * 1000;                           // Set client time out value

            if (configuration.RequestMethod == RequestMethodType.Post)
            {
                request.ContentLength = configuration.RequestParameters.Length;

                // Send request message
                using (StreamWriter sw = new StreamWriter(request.GetRequestStream()/*, Encoding.UTF8*/))
                {
                    sw.Write(configuration.RequestParameters);
                }
            }

            // Get response from server
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            ResponseResult responseResult = new ResponseResult();
            using (StreamReader responseReader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet)))
            {
                responseResult.StatusCode = (int)response.StatusCode;
                responseResult.ResponseString = responseReader.ReadToEnd();
            }

            return responseResult;
        }

        #region Protect and private method
        protected bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            // Always accept
            return true;
        }

        private void LoadActions(HttpWebRequest request)
        {
            if (!string.IsNullOrEmpty(configuration.CertificateInfo))
            {
                request.ClientCertificates.Add(CertificateHelper.GetCertificate1(EnvironmentHelper.ExpandEnvironmentVariables(configuration.CertificateInfo), configuration.CertificatePassword));
            }
            if (!string.IsNullOrEmpty(configuration.CredentialUserName) && !string.IsNullOrEmpty(configuration.CertificatePassword))
            {
                if (string.IsNullOrEmpty(configuration.CredentialDomain))
                {
                    request.Credentials = new NetworkCredential(configuration.CredentialUserName, configuration.CredentialPassword);
                }
                else
                {
                    request.Credentials = new NetworkCredential(configuration.CredentialUserName, configuration.CredentialPassword, configuration.CredentialDomain);
                }
            }
        }

        private static string UrlEncode(string requestParameters)
        {
            StringBuilder sb = new StringBuilder();
            Dictionary<string, string> parameters = HttpHelper.ParseRequestString2Parameters(requestParameters);
            foreach (var p in parameters)
            {
                sb.Append(string.Format("{0}={1}&", p.Key, HttpUtility.UrlEncode(p.Value)));
            }

            return sb.ToString().Trim('&');
        }
        #endregion
    }
    public class ResponseResult
    {
        public int StatusCode { get; set; }
        public string ResponseString { get; set; }
    }

    public enum RequestMethodType
    {
        Get = 1,
        Post = 2,
    }
}
